// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraPlayerState.h"

#include "AbilitySystem/Attributes/LyraCombatSet.h"
#include "AbilitySystem/Attributes/LyraHealthSet.h"
#include "AbilitySystem/LyraAbilitySet.h"
#include "AbilitySystem/LyraAbilitySystemComponent.h"
#include "Character/LyraPawnData.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "Components/GameFrameworkComponentManager.h"
#include "Engine/World.h"
#include "GameFramework/GameplayMessageSubsystem.h"
#include "GameModes/LyraExperienceManagerComponent.h"
//@TODO: 希望更好地隔离这部分，以便在不了解其他内容的情况下获取角色数据
#include "GameModes/LyraGameMode.h"
#include "LyraLogChannels.h"
#include "LyraPlayerController.h"
#include "Messages/LyraVerbMessage.h"
#include "Net/UnrealNetwork.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraPlayerState)

class AController;
class APlayerState;
class FLifetimeProperty;

const FName ALyraPlayerState::NAME_LyraAbilityReady("LyraAbilitiesReady"); // 初始化Lyra技能准备就绪名称

/**
 * 构造函数
 */
ALyraPlayerState::ALyraPlayerState(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
	, MyPlayerConnectionType(ELyraPlayerConnectionType::Player) // 初始化玩家连接类型为玩家
{
	AbilitySystemComponent = ObjectInitializer.CreateDefaultSubobject<ULyraAbilitySystemComponent>(this, TEXT("AbilitySystemComponent")); // 创建技能系统组件
	AbilitySystemComponent->SetIsReplicated(true); // 设置组件需要复制
	AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); // 设置复制模式为混合

	// 这些属性集将被AbilitySystemComponent::InitializeComponent检测到。保留引用以防止这些集在被初始化之前被垃圾回收。
	HealthSet = CreateDefaultSubobject<ULyraHealthSet>(TEXT("HealthSet")); // 创建生命值属性集
	CombatSet = CreateDefaultSubobject<ULyraCombatSet>(TEXT("CombatSet")); // 创建战斗属性集

	// AbilitySystemComponent需要以高频率更新。
	SetNetUpdateFrequency(100.0f); // 设置网络更新频率

	MyTeamID = FGenericTeamId::NoTeam; // 初始化队伍ID为无队伍
	MySquadID = INDEX_NONE; // 初始化小队ID为无效值
}

/**
 * 预初始化组件
 */
void ALyraPlayerState::PreInitializeComponents()
{
	Super::PreInitializeComponents(); // 调用父类实现
}

/**
 * 重置
 */
void ALyraPlayerState::Reset()
{
	Super::Reset(); // 调用父类实现
}

/**
 * 客户端初始化
 */
void ALyraPlayerState::ClientInitialize(AController* C)
{
	Super::ClientInitialize(C); // 调用父类实现

	if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(GetPawn())) // 查找角色扩展组件
	{
		PawnExtComp->CheckDefaultInitialization(); // 检查默认初始化
	}
}

/**
 * 复制属性
 */
void ALyraPlayerState::CopyProperties(APlayerState* PlayerState)
{
	Super::CopyProperties(PlayerState); // 调用父类实现

	//@TODO: 复制统计信息
}

/**
 * 停用时调用
 */
void ALyraPlayerState::OnDeactivated()
{
	bool bDestroyDeactivatedPlayerState = false; // 是否销毁停用的玩家状态

	switch (GetPlayerConnectionType()) // 根据玩家连接类型判断
	{
		case ELyraPlayerConnectionType::Player:
		case ELyraPlayerConnectionType::InactivePlayer:
			//@TODO: 询问经验系统是否应该立即销毁断开连接的玩家或保留它们
			// （例如，对于长时间运行的服务器，如果大量玩家循环通过，可能会积累）
			bDestroyDeactivatedPlayerState = true; // 设置为销毁
			break;
		default:
			bDestroyDeactivatedPlayerState = true; // 默认设置为销毁
			break;
	}
	
	SetPlayerConnectionType(ELyraPlayerConnectionType::InactivePlayer); // 设置玩家连接类型为非活跃玩家

	if (bDestroyDeactivatedPlayerState) // 如果需要销毁
	{
		Destroy(); // 销毁对象
	}
}

/**
 * 重新激活时调用
 */
void ALyraPlayerState::OnReactivated()
{
	if (GetPlayerConnectionType() == ELyraPlayerConnectionType::InactivePlayer) // 如果当前是非活跃玩家
	{
		SetPlayerConnectionType(ELyraPlayerConnectionType::Player); // 设置为活跃玩家
	}
}

/**
 * 经验加载完成回调
 */
void ALyraPlayerState::OnExperienceLoaded(const ULyraExperienceDefinition* /*CurrentExperience*/)
{
	if (ALyraGameMode* LyraGameMode = GetWorld()->GetAuthGameMode<ALyraGameMode>()) // 获取Lyra游戏模式
	{
		if (const ULyraPawnData* NewPawnData = LyraGameMode->GetPawnDataForController(GetOwningController())) // 获取控制器对应的角色数据
		{
			SetPawnData(NewPawnData); // 设置角色数据
		}
		else
		{
			UE_LOG(LogLyra, Error, TEXT("ALyraPlayerState::OnExperienceLoaded(): Unable to find PawnData to initialize player state [%s]!"), *GetNameSafe(this)); // 记录错误日志
		}
	}
}

/**
 * 获取生命周期复制属性
 */
void ALyraPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 调用父类实现

	FDoRepLifetimeParams SharedParams; // 创建复制参数
	SharedParams.bIsPushBased = true; // 设置为基于推送的复制

	DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, PawnData, SharedParams); // 注册PawnData属性复制
	DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MyPlayerConnectionType, SharedParams) // 注册MyPlayerConnectionType属性复制
	DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MyTeamID, SharedParams); // 注册MyTeamID属性复制
	DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MySquadID, SharedParams); // 注册MySquadID属性复制

	SharedParams.Condition = ELifetimeCondition::COND_SkipOwner; // 设置复制条件为跳过所有者
	DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, ReplicatedViewRotation, SharedParams); // 注册ReplicatedViewRotation属性复制

	DOREPLIFETIME(ThisClass, StatTags);	// 注册StatTags属性复制
}

/**
 * 获取复制的视图旋转
 */
FRotator ALyraPlayerState::GetReplicatedViewRotation() const
{
	// 可以用自定义复制替换这个
	return ReplicatedViewRotation; // 返回复制的视图旋转
}

/**
 * 设置复制的视图旋转
 */
void ALyraPlayerState::SetReplicatedViewRotation(const FRotator& NewRotation)
{
	if (NewRotation != ReplicatedViewRotation) // 如果旋转发生变化
	{
		MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, ReplicatedViewRotation, this); // 标记属性为脏
		ReplicatedViewRotation = NewRotation; // 更新复制的视图旋转
	}
}

/**
 * 获取Lyra玩家控制器
 */
ALyraPlayerController* ALyraPlayerState::GetLyraPlayerController() const
{
	return Cast<ALyraPlayerController>(GetOwner()); // 转换并返回所有者作为Lyra玩家控制器
}

/**
 * 获取技能系统组件
 */
UAbilitySystemComponent* ALyraPlayerState::GetAbilitySystemComponent() const
{
	return GetLyraAbilitySystemComponent(); // 返回Lyra技能系统组件
}

/**
 * 后初始化组件
 */
void ALyraPlayerState::PostInitializeComponents()
{
	Super::PostInitializeComponents(); // 调用父类实现

	check(AbilitySystemComponent); // 检查技能系统组件是否有效
	AbilitySystemComponent->InitAbilityActorInfo(this, GetPawn()); // 初始化技能角色信息

	UWorld* World = GetWorld(); // 获取世界
	if (World && World->IsGameWorld() && World->GetNetMode() != NM_Client) // 如果是游戏世界且不是客户端
	{
		AGameStateBase* GameState = GetWorld()->GetGameState(); // 获取游戏状态
		check(GameState); // 检查游戏状态是否有效
		ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>(); // 查找经验管理器组件
		check(ExperienceComponent); // 检查经验管理器组件是否有效
		ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded)); // 注册经验加载回调
	}
}

/**
 * 设置角色数据
 */
void ALyraPlayerState::SetPawnData(const ULyraPawnData* InPawnData)
{
	check(InPawnData); // 检查输入的角色数据是否有效

	if (GetLocalRole() != ROLE_Authority) // 如果不是权威端
	{
		return; // 直接返回
	}

	if (PawnData) // 如果已经存在角色数据
	{
		UE_LOG(LogLyra, Error, TEXT("Trying to set PawnData [%s] on player state [%s] that already has valid PawnData [%s]."), *GetNameSafe(InPawnData), *GetNameSafe(this), *GetNameSafe(PawnData)); // 记录错误日志
		return; // 直接返回
	}

	MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, PawnData, this); // 标记属性为脏
	PawnData = InPawnData; // 设置角色数据

	for (const ULyraAbilitySet* AbilitySet : PawnData->AbilitySets) // 遍历角色数据中的技能集
	{
		if (AbilitySet) // 如果技能集有效
		{
			AbilitySet->GiveToAbilitySystem(AbilitySystemComponent, nullptr); // 将技能集赋予技能系统
		}
	}

	UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, NAME_LyraAbilityReady); // 发送游戏框架组件扩展事件
	
	ForceNetUpdate(); // 强制网络更新
}

/**
 * 角色数据复制回调
 */
void ALyraPlayerState::OnRep_PawnData()
{
}

/**
 * 设置玩家连接类型
 */
void ALyraPlayerState::SetPlayerConnectionType(ELyraPlayerConnectionType NewType)
{
	MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MyPlayerConnectionType, this); // 标记属性为脏
	MyPlayerConnectionType = NewType; // 更新玩家连接类型
}

/**
 * 设置小队ID
 */
void ALyraPlayerState::SetSquadID(int32 NewSquadId)
{
	if (HasAuthority()) // 如果有权威
	{
		MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MySquadID, this); // 标记属性为脏

		MySquadID = NewSquadId; // 更新小队ID
	}
}

/**
 * 设置通用队伍ID
 */
void ALyraPlayerState::SetGenericTeamId(const FGenericTeamId& NewTeamID)
{
	if (HasAuthority()) // 如果有权威
	{
		const FGenericTeamId OldTeamID = MyTeamID; // 保存旧队伍ID

		MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MyTeamID, this); // 标记属性为脏
		MyTeamID = NewTeamID; // 更新队伍ID
		ConditionalBroadcastTeamChanged(this, OldTeamID, NewTeamID); // 条件广播队伍改变
	}
	else
	{
		UE_LOG(LogLyraTeams, Error, TEXT("Cannot set team for %s on non-authority"), *GetPathName(this)); // 记录错误日志
	}
}

/**
 * 获取通用队伍ID
 */
FGenericTeamId ALyraPlayerState::GetGenericTeamId() const
{
	return MyTeamID; // 返回队伍ID
}

/**
 * 获取队伍索引改变委托
 */
FOnLyraTeamIndexChangedDelegate* ALyraPlayerState::GetOnTeamIndexChangedDelegate()
{
	return &OnTeamChangedDelegate; // 返回队伍改变委托
}

/**
 * 队伍ID复制回调
 */
void ALyraPlayerState::OnRep_MyTeamID(FGenericTeamId OldTeamID)
{
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播队伍改变
}

/**
 * 小队ID复制回调
 */
void ALyraPlayerState::OnRep_MySquadID()
{
	//@TODO: 通知小队子系统（一旦存在）
}

/**
 * 添加统计标签堆栈
 */
void ALyraPlayerState::AddStatTagStack(FGameplayTag Tag, int32 StackCount)
{
	StatTags.AddStack(Tag, StackCount); // 向统计标签容器添加堆栈
}

/**
 * 移除统计标签堆栈
 */
void ALyraPlayerState::RemoveStatTagStack(FGameplayTag Tag, int32 StackCount)
{
	StatTags.RemoveStack(Tag, StackCount); // 从统计标签容器移除堆栈
}

/**
 * 获取统计标签堆栈计数
 */
int32 ALyraPlayerState::GetStatTagStackCount(FGameplayTag Tag) const
{
	return StatTags.GetStackCount(Tag); // 返回统计标签堆栈计数
}

/**
 * 检查是否有统计标签
 */
bool ALyraPlayerState::HasStatTag(FGameplayTag Tag) const
{
	return StatTags.ContainsTag(Tag); // 返回是否包含统计标签
}

/**
 * 客户端广播消息实现
 */
void ALyraPlayerState::ClientBroadcastMessage_Implementation(const FLyraVerbMessage Message)
{
	// 这个检查是为了防止在独立模式下运行动作
	if (GetNetMode() == NM_Client) // 如果是客户端
	{
		UGameplayMessageSubsystem::Get(this).BroadcastMessage(Message.Verb, Message); // 广播消息
	}
}